﻿using System;
using System.Runtime.InteropServices;

namespace Framework.Core.Com
{
    /// <summary>
    /// VARIANT: this is equivalent to "Object" in VB. It's the universal variable type for COM.
    /// </summary>
    /// <remarks>The "vt" flag determines which of the other fields have meaning. vt is a VarEnum.</remarks>
    [StructLayout(LayoutKind.Explicit, Size = 16)]
    public struct VARIANT
    {

        [FieldOffset(0)]
        public ushort vt;

        [FieldOffset(2)]
        public ushort wReserved1;

        [FieldOffset(4)]
        public ushort wReserved2;

        [FieldOffset(6)]
        public ushort wReserved3;

        [FieldOffset(8)]
        public long llVal;

        [FieldOffset(8)]
        public int lVal;

        [FieldOffset(8)]
        public byte bVal;

        [FieldOffset(8)]
        public short iVal;

        [FieldOffset(8)]
        public float fltVal;

        [FieldOffset(8)]
        public double dblVal;

        [FieldOffset(8)]
        public short boolVal;

        [FieldOffset(8)]
        public int scode;

        [FieldOffset(8)]
        public double date;

        [FieldOffset(8)]
        public byte cVal;

        [FieldOffset(8)]
        public ushort uiVal;

        [FieldOffset(8)]
        public UInt32 ulVal;

        [FieldOffset(8)]
        public ulong ullVal;

        [FieldOffset(8)]
        public int intVal;

        [FieldOffset(8)]
        public UInt32 uintVal;

        [FieldOffset(8)]
        public IntPtr ptr;

        //  <summary>
        //  GetObject: returns a .NET Object equivalent for this Variant.
        //  </summary>
        object GetObject()
        {
            //  We want to use the handy Marshal.GetObjectForNativeVariant.
            //  But this only operates upon an IntPtr to a block of memory.
            //  So we first flatten ourselves into that block of memory. (size 16)
            IntPtr ptr = Marshal.AllocCoTaskMem(16);
            Marshal.StructureToPtr(this, ptr, false);

            try
            {
                return Marshal.GetObjectForNativeVariant(ptr);
            }
            finally
            {
                Marshal.FreeCoTaskMem(ptr);
            }
        }
    }

}
